import * as lsp from "vscode-languageserver/node";
import {
    DsProperties,
    DsWindowProperties,
    DsWindowPropertiesUpdateParams,
    DsWorkspacePropertiesUpdateParams,
    LanguageNotifications,
    LanguageRequests,
    OpenDialogOptions,
    QuickPickOptions,
    SelectFileBranchParams,
    SetProgramMetadataParams
} from "../common/types";
import { Diagnostic } from "./diagnostic";
import { t } from "./analysis";

export interface LspIntrinsicType extends t.IntrinsicType {
    completions: lsp.CompletionList;
}

export interface LspType extends t.Type {
    completions: lsp.CompletionList;
}

export interface LspObjectType extends t.ObjectType {
    completions: lsp.CompletionList;
}

export interface LanguageService {
    readonly capabilities: lsp.ServerCapabilities;
    getSemanticDiagnostics(fileName: string): Diagnostic[];
    getCompletionsAtPosition(fileName: string, position: number): lsp.CompletionItem[] | lsp.CompletionList;
    getHoverAtPosition(fileName: string, position: number): lsp.Hover | undefined;
    getDefinitionAtPosition(fileName: string, position: number): lsp.Definition | null;
    getReferenceAtPosition(fileName: string, position: number): lsp.Location[] | null;
    getSignatureHelpAtPosition(fileName: string, position: number): lsp.SignatureHelp | undefined;
    getRenameInformationAtPosition(fileName: string, position: number): lsp.WorkspaceEdit | null;
    getDocumentSymbols(fileName: string): lsp.DocumentSymbol[] | undefined;
    getDocumentHighlight(fileName: string): lsp.DocumentHighlight[] | undefined;
}

interface LanguageServerRequestTypes {
    [LanguageRequests.showOpenFileDialog]: lsp.RequestType<OpenDialogOptions, string[] | undefined, void>;
    [LanguageRequests.showQuickPickFile]: lsp.RequestType<QuickPickOptions, string | undefined, void>,
    [LanguageRequests.getConfiguration]: lsp.RequestType<string, DsProperties, void>;
    [LanguageRequests.getProgramMetadata]: lsp.RequestType<string, string | undefined, void>;
    [LanguageRequests.setProgramMetadata]: lsp.RequestType<SetProgramMetadataParams, void, void>;
    [LanguageRequests.getFileBranches]: lsp.RequestType<string, string[], void>;
    [LanguageRequests.getFileCurrentBranch]: lsp.RequestType<string, string, void>;
    [LanguageRequests.selectFileBranch]: lsp.RequestType<SelectFileBranchParams, void, void>;
    [LanguageRequests.getWindowConfiguration]: lsp.RequestType<void, DsProperties, void>;
}

export const languageServerRequests: LanguageServerRequestTypes = {
    [LanguageRequests.showOpenFileDialog]: new lsp.RequestType(LanguageRequests.showOpenFileDialog),
    [LanguageRequests.showQuickPickFile]: new lsp.RequestType(LanguageRequests.showQuickPickFile),
    [LanguageRequests.getConfiguration]: new lsp.RequestType(LanguageRequests.getConfiguration),
    [LanguageRequests.getProgramMetadata]: new lsp.RequestType(LanguageRequests.getProgramMetadata),
    [LanguageRequests.setProgramMetadata]: new lsp.RequestType(LanguageRequests.setProgramMetadata),
    [LanguageRequests.getFileBranches]: new lsp.RequestType(LanguageRequests.getFileBranches),
    [LanguageRequests.getFileCurrentBranch]: new lsp.RequestType(LanguageRequests.getFileCurrentBranch),
    [LanguageRequests.selectFileBranch]: new lsp.RequestType(LanguageRequests.selectFileBranch),
    [LanguageRequests.getWindowConfiguration]: new lsp.RequestType(LanguageRequests.getWindowConfiguration),
};

interface LanguageServerNotifications {
    [LanguageNotifications.showEditor]: lsp.NotificationType<string>;
    [LanguageNotifications.closeActivateEditor]: lsp.NotificationType<string>;
    [LanguageNotifications.initializeServerWindowConfigurations]: lsp.NotificationType<DsWindowProperties>;
    [LanguageNotifications.configurationChanged]: lsp.NotificationType<DsWindowPropertiesUpdateParams>;
    [LanguageNotifications.workspaceConfigurationChanged]: lsp.NotificationType<DsWorkspacePropertiesUpdateParams>;
}

export const languageServerNotifications: LanguageServerNotifications = {
    [LanguageNotifications.showEditor]: new lsp.NotificationType(LanguageNotifications.showEditor),
    [LanguageNotifications.closeActivateEditor]: new lsp.NotificationType(LanguageNotifications.closeActivateEditor),
    [LanguageNotifications.initializeServerWindowConfigurations]: new lsp.NotificationType(LanguageNotifications.initializeServerWindowConfigurations),
    [LanguageNotifications.configurationChanged]: new lsp.NotificationType(LanguageNotifications.configurationChanged),
    [LanguageNotifications.workspaceConfigurationChanged]: new lsp.NotificationType(LanguageNotifications.workspaceConfigurationChanged),
};

export const enum LanguageServerCommand {
    diagnostic = "diagnostic",
    completion = "completion",
    signatureHelp = "signatureHelp",
    codeAction = "codeAction",
    hover = "hover",
    documentHighlight = "documentHighlight",
    definition = "definition",
    reference = "reference",
    rename = "rename",
    documentSymbol = "documentSymbol",
    foldingRange = "foldingRange",
}

export interface LanguageServerCommandTypes {
    [LanguageServerCommand.diagnostic]: [lsp.TextDocumentPositionParams, Promise<lsp.Disposable[] | null>];
    [LanguageServerCommand.completion]: [lsp.CompletionParams, Promise<lsp.CompletionList>];
    [LanguageServerCommand.signatureHelp]: [lsp.SignatureHelpParams, Promise<lsp.SignatureHelp | null>];
    [LanguageServerCommand.codeAction]: [lsp.CodeActionParams, Promise<lsp.CodeAction[]>];
    [LanguageServerCommand.hover]: [lsp.HoverParams, Promise<lsp.Hover | null>];
    [LanguageServerCommand.documentHighlight]: [lsp.DocumentHighlightParams, Promise<lsp.DocumentHighlight[] | undefined>];
    [LanguageServerCommand.definition]: [lsp.DefinitionParams, Promise<lsp.Definition | lsp.DefinitionLink[] | null>];
    [LanguageServerCommand.reference]: [lsp.ReferenceParams, Promise<lsp.Location[] | null>];
    [LanguageServerCommand.rename]: [lsp.RenameParams, Promise<lsp.WorkspaceEdit | null>];
    [LanguageServerCommand.documentSymbol]: [lsp.DocumentSymbolParams, Promise<lsp.DocumentSymbol[] | undefined>];
    [LanguageServerCommand.foldingRange]: [lsp.FoldingRangeParams, Promise<lsp.FoldingRange[] | undefined>];
}
